feat(renderer): randomize star field seeds#22
Merged
kunchenguid merged 9 commits intomainfrom Apr 3, 2026
Merged
Conversation
# Conflicts: # src/renderer.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This change makes the renderer's star field feel unique per run by generating per-instance seeds instead of reusing fixed ones. It also hardens the terminal layout pipeline so wide Unicode graphemes, emoji, and full-width characters wrap, measure, and clamp correctly without breaking centered content or side-star alignment.
Risk Assessment: 🟡 Medium — Tests are strong, but a known correctness gap remains in the new width heuristic on a core rendering path.
Architecture
flowchart TD subgraph renderer_flow["Renderer Flow"] direction TB renderer_cls["Renderer (updated)"] session_seeds["Session Star Seeds (updated)"] star_gen["generateStarField (unchanged)"] frame_builder["buildFrameCells (updated)"] terminal_frame["Terminal Frame Output (unchanged)"] renderer_cls -->|"creates once"| session_seeds session_seeds -->|"seed top/bottom/side fields"| star_gen renderer_cls -->|"rebuilds frame"| frame_builder star_gen -->|"provides star positions"| frame_builder frame_builder -->|"renders centered scene"| terminal_frame end subgraph text_layout["Unicode Layout Support"] direction TB terminal_width["terminal-width utils (added)"] word_wrap["wordWrap (updated)"] cell_encoder["Cell Encoding in renderer-diff (updated)"] width_clamp["Cell Width Clamp (updated)"] terminal_width -->|"measures grapheme display width"| word_wrap terminal_width -->|"sets per-cell widths"| cell_encoder word_wrap -->|"supplies wrapped prompt/message lines"| frame_builder cell_encoder -->|"supplies cell arrays"| frame_builder width_clamp -->|"prevents content overflow"| frame_builder endKey changes made
Renderernow creates stable random seeds for the top, bottom, and side star fields once per instance, then reuses them across renders and resizes.terminal-widthutilities built onIntl.Segmenterto split graphemes and compute display width for combining marks, full-width glyphs, and emoji.wordWrap,renderer-diff, and frame centering to use grapheme-aware widths, preserve wide glyphs at line boundaries, and avoid overflowing the 63-column content area.How was this tested
npm test, which builds the project and runs the full Vitest suite. Result: 27 test files passed, 249 tests passed, including the new renderer, word-wrap, terminal-width, and existing e2e coverage. I also ran a manual CLI smoke test against the built binary with a boundary-case prompt of 62As plus🌕; it exited with code 0 and the captured terminal output showed the wide glyph wrapped onto its own line rather than being dropped or merged incorrectly.Critique Comments
src/utils/terminal-width.ts:52 - UsingExtended_Pictographicas a blanket 2-column signal misclassifies plain text symbols like©,™,❤,✈, and⚙as wide even without emoji presentation. That makes prompts/messages wrap and truncate a column early; restrict the fast-path to actual emoji presentation sequences (VS16/ZWJ/keycap/flags) or East Asian wide code points.